import Link from "next/link"; import { notFound } from "next/navigation"; import { ArrowLeft, ArrowRight, KeyRound } from "lucide-react"; import { PLAN_LIMITS, normalizePlan } from "@fetcha/core"; import { getWorkspace } from "@/lib/session"; import { getOrgProject, listApiKeys, monthlyUsage } from "@/lib/queries/account"; import { formatDate, formatDateOnly, formatNumber, formatPercent, formatUsd, timeAgo } from "@/lib/format"; import { maskedKey } from "@/lib/account-snippets"; import { PageHeader, SectionTitle } from "@/components/ui/page-header"; import { Badge, StatusBadge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Stat, StatGrid } from "@/components/ui/stat"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { EmptyState } from "@/components/ui/empty-state"; import { Alert } from "@/components/ui/alert"; import { ProjectForm } from "@/components/dashboard/projects/project-form"; import { ArchiveProjectButton, SelectProjectButton } from "@/components/dashboard/projects/project-actions"; import { CreateKeyDialog } from "@/components/dashboard/api-keys/create-key-dialog"; export const dynamic = "force-dynamic"; export default async function ProjectDetailPage({ params }: { params: Promise<{ id: string }> }) { const { id } = await params; const ws = await getWorkspace(); const project = await getOrgProject(ws.organization.id, id); if (!project) notFound(); const [usage, keys] = await Promise.all([monthlyUsage(ws.organization.id, project.id), listApiKeys(ws.organization.id, project.id)]); const activeKeys = keys.filter((k) => k.status === "active"); const current = ws.project.id === project.id; const archived = Boolean(project.archivedAt); const planLimits = PLAN_LIMITS[normalizePlan(ws.organization.plan)]; const requestCap = project.monthlyRequestLimit ?? planLimits.monthly_requests; const requestPct = requestCap > 0 && requestCap < Number.MAX_SAFE_INTEGER ? Math.min(100, (usage.requests / requestCap) * 100) : null; const spendPct = project.hardLimitUsd ? Math.min(100, (usage.spendUsd / project.hardLimitUsd) * 100) : null; return (
Organization-wide limits live in{" "} Settings .